EC2 Instance Connect Endpoint経由でRDSに接続してみた

EC2 Instance Connect Endpoint経由でRDSに接続してみた

Clock Icon2023.06.15

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

2023/06/28 追記 : 利用可能ポートが制限されました

公開当時の内容

しばたです。

前に書いた記事でEC2 Instance Connect Endpointの接続はWebSocketトンネルを介したものであると説明しました。
また、プロトコルもSSHだけに制限されておらずRDPも使用可能でした。

AWS CLIの実装を読み解く限りこの機能のメインはWebSocketトンネルを張る事でありプロトコルにも依存していません。
そうなると「別にEC2インスタンスに限らず、たとえばRDSインスタンスに対してもトンネルを張れるのでは?」と考えるのは必然でしょう。

試してみた

というわけで実際に試してみました。

検証環境

前回の記事で用意したVPC環境にRDS for PostgreSQL 15.3のインスタンスを用意しました。

RDS for PostgreSQLを選んだのは単純に私が使い慣れてるだけであり他のRDBMSでも問題ないでしょう。
その他の情報は以下の通りです。

  • VPC内のPrivateサブネットはインターネットアクセス不可
  • RDS for PostgreSQL 15.3はSingle AZ構成で待ち受けポートはデフォルトのまま(TCP 5432)
    • パラメーターグループとオプショングループはデフォルトのものを使用
    • セキュリティグループでVPC Endpointからの接続(TCP 5432)を許可
  • VPC EndpointのセキュリティグループでTCP 5432のアウトバウンド通信を許可
  • クライアント環境でAWS CLIを利用可能に初期設定済み
    • your_profileという名前のプロファイルを設定済み

補足1 : VPC Endpointのセキュリティグループ設定

VPC Endpointセキュリティグループのアウトバウンド通信制御はこんな感じになっていればOKです。
RDSインスタンスに対してTCP 5432で通信するためアウトバウンド通信を許可しておきます。

インバウンド通信は全てブロックして構いません。

補足2 : RDSインスタンスのセキュリティグループ設定

RDSインスタンス側のセキュリティグループはVPC Endpointからのインバウンド通信を許可しておきます。

1. aws ec2-instance-connect open-tunnel コマンドの実行

接続までの手順はWindows ServerにRDP接続した時とほぼ同じです。

最初にクライアントでaws ec2-instance-connect open-tunnelコマンドを使用しRDSインスタンスに対してWebSocketトンネルを張ります。
このコマンドの基本的な使い方は--instance-idパラメーターで宛先EC2インスタンスIDを指定しており、このままではRDSに接続できません。

基本的な利用方法
# EC2インスタンスIDを指定してWebSocketトンネルを張る
aws ec2-instance-connect open-tunnel --instance-id "宛先インスタンスID" --remote-port 3389 --local-port "任意の空きポート"

上記指定をした際は

  • 宛先インスタンス情報からインスタンスのPrivate IPアドレスを取得
  • 宛先インスタンスの配置されているVPCおよびサブネット情報からVPC Endpointを探索する

といった作業を内部で行っています。
WebSocketトンネルを張るのに必要な情報は「VPC EndpointのPublic DNS名」「宛先Private IPアドレス」「宛先ポート番号」「ローカルポート番号」であり、このうち「VPC EndpointのPublic DNS名」「宛先Private IPアドレス」の2つをどうにかしてコマンドに渡してやる必要があります。

「宛先Private IPアドレス」はRDSのDNSエンドポイントを名前解決してやれば取得できます。

# 例えばPowerShellからだとこんな感じでRDSの名前解決が可能 : 今回の環境では 10.0.21.157 がRDSのIPアドレス
PS C:\> Resolve-DnsName -Name test-postgres.xxxxxxxxxx.ap-northeast-1.rds.amazonaws.com -Type A | Select-Object IPAddress

IPAddress
---------
10.0.21.157

そしてありがたいことにこのコマンドには--instance-connect-endpoint-id, --private-ip-addressパラメーターが存在しています。
「VPC EndpointのPublic DNS名」は--instance-connect-endpoint-idを指定してやればコマンド内部で取得してくれます。[1]

このため以下の指定でWebSocketトンネルを張ることができます。

今回の利用方法
# VPC Endpoint IDおよび宛先Private IPアドレスを直接指定してトンネルを張ることも可能
aws ec2-instance-connect open-tunnel --instance-connect-endpoint-id "VPC Endpoint ID"--private-ip-address "宛先Private IP"--local-port "任意の空きポート" --remote-port 5432

実行例はこんな感じ。

# 今回の実行例
PS C:\> $env:AWS_PROFILE="your_profile"
PS C:\> aws ec2-instance-connect open-tunnel --instance-connect-endpoint-id eice-xxxxxxxxxxxx --private-ip-address 10.0.21.157 --local-port 15432 --remote-port 5432

設定に問題がなければエラー無くWebSocketトンネルが張れるはずです。

2. RDSインスタンスへ接続

あとはlocalhost:15432 (127.0.0.1:15432)に接続すればPostgreSQLを操作できます。

(pgAdmin 4で接続する場合)

(VPC EndpointのIP 10.0.21.136 から接続された扱いになっている)

最後に

以上となります。

今回はRDSを例にしましたがVPCからIPv4で到達可能であれば様々なAWSリソースに対して接続できるはずです。
無限に応用できると思いますので是非活用してみてください。

脚注
  1. ちなみに--instance-connect-endpoint-dns-nameパラメーターも存在し、直接Public DNS名を引き渡すことも可能です ↩︎

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.